<template>
  <el-container style="width: 100%;height: 100%;">
    <!--    <el-container style="width: 100%;height: 100%;">-->
    <el-main
      style="height: 100%;margin-right: 10px;border-color: #E4E7ED;border-width: 10px"
    >
      <el-form>
        <el-row style="height: 100%">
          <el-col style="width: 320px">
            <el-form-item label="原始数据类型:">
              <div style="text-align: left">
                <!--              el-select默认居中显示，外面加一层div控制位置-->
                <el-select v-model="srcDataType" placeholder="请选择">
                  <el-option
                    v-for="item in srcDataTypeList"
                    :key="item.idx"
                    :label="item.value"
                    :value="item.value"
                  ></el-option>
                </el-select>
              </div>
            </el-form-item>
          </el-col>
          <el-col style="width: 300px" v-show="srcCharDataShow">
            <el-form-item label="字符类型:">
              <div style="text-align: left">
                <!--              el-select默认居中显示，外面加一层div控制位置-->
                <el-select v-model="charDataType" placeholder="请选择">
                  <el-option
                    v-for="item in charDataTypeList"
                    :key="item.idx"
                    :label="item.value"
                    :value="item.value"
                  ></el-option>
                </el-select>
              </div>
            </el-form-item>
          </el-col>
          <el-input
            type="textarea"
            :rows="10"
            placeholder="请输入内容"
            v-model="srcTextarea"
            style="margin-top: 5px"
          >
          </el-input>
        </el-row>
      </el-form>

      <el-form style="margin-top: 10px">
        <el-row style="height: 100%">
          <el-form-item label="结果数据类型:">
            <el-select v-model="dstDataType" placeholder="请选择">
              <el-option
                v-for="item in dstDataTypeList"
                :key="item.idx"
                :label="item.value"
                :value="item.value"
              ></el-option>
            </el-select>
            <el-button
              style="margin-left: 5px"
              v-on:click="fLowerCase"
              v-show="showLowerCaseBtn"
              >lowercaseString</el-button
            >
            <el-input
              type="textarea"
              :rows="10"
              placeholder="显示结果"
              v-model="dstTextarea"
              style="margin-top: 5px"
            >
            </el-input>
          </el-form-item>
        </el-row>
      </el-form>
      <el-row>
        <el-button
          type="primary"
          style="width: 200px"
          v-on:click="fEncrypt('en')"
          >加密</el-button
        >
        <el-button
          type="primary"
          style="width: 200px"
          v-on:click="fEncrypt('de')"
          >解密</el-button
        >
      </el-row>
    </el-main>

    <!--    <el-aside-->
    <!--      style="width: 300px;border-left-color: #c8c8c8;border-left-style: solid;border-left-width: 1px;height: 100%"-->
    <!--    >-->
    <el-aside>
      <el-form style="margin-left: 15px;">
        <!--          <el-form-item style="color: chocolate">配置参数</el-form-item>-->
        <el-form-item label="加密类型:">
          <el-select v-model="encryptType" placeholder="请选择">
            <el-option
              v-for="item in encryptTypeList"
              :key="item.idx"
              :label="item.value"
              :value="item.value"
            ></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="密钥字符类型:">
          <el-select
            v-model="encryptStringType"
            placeholder="请选择"
            style="width: 180px"
          >
            <el-option
              v-for="item in encryptStringTypeList"
              :key="item.idx"
              :label="item.value"
              :value="item.value"
            ></el-option>
          </el-select>
          <el-input
            type="textarea"
            :rows="3"
            placeholder="请输入密钥(长度与分组长度一致) DES:8字节,3DES:24字节,AES128:16字节 AES256：32字节"
            v-model="encryptKeyTextarea"
            style="margin-top: 5px"
          >
          </el-input>
        </el-form-item>

        <el-form-item label="初始化向量字符类型:">
          <el-select
            v-model="initVectorStringType"
            placeholder="请选择"
            style="width: 140px"
          >
            <el-option
              v-for="item in initVectorStringTypeList"
              :key="item.idx"
              :label="item.value"
              :value="item.value"
            ></el-option>
          </el-select>
          <el-input
            type="textarea"
            :rows="3"
            placeholder="ECB分组模式不需要, 与分组长度一致 DES:8字节,3DES:24字节,AES128:16字节 AES256：32字节 "
            v-model="srcInitVectorTextarea"
            style="margin-top: 5px"
          >
          </el-input>
        </el-form-item>

        <el-form-item label="分组模式(block):">
          <el-select
            v-model="blockType"
            placeholder="请选择"
            style="width: 160px"
          >
            <el-option
              v-for="item in blockTypeList"
              :key="item.idx"
              :label="item.value"
              :value="item.value"
            ></el-option>
          </el-select>
        </el-form-item>

        <el-form-item label="补位(padding):">
          <el-select
            v-model="paddingType"
            placeholder="请选择"
            style="width: 160px"
          >
            <el-option
              v-for="item in paddingTypeList"
              :key="item.idx"
              :label="item.value"
              :value="item.value"
            ></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="ISO10126Padding 补位为随机数，最后一位表示补位长度，所以每次加密结果补位部分是不一样的">
        </el-form-item>
      </el-form>
    </el-aside>
  </el-container>
</template>

<script>
import Crypto from "crypto-js";
import { Hex } from "../JS/hex";
import { SM4 } from "../JS/sm4-1.0";

export default {
  name: "Encrypt",
  data() {
    return {
      srcDataTypeList: [
        { value: "plain", idx: "1" },
        { value: "hex", idx: "2" },
        { value: "base64", idx: "3" }
      ],
      srcDataType: "plain",
      srcTextarea: "",

      dstDataTypeList: [
        { value: "hex", idx: "1" },
        { value: "base64", idx: "2" }
      ],
      dstDataType: "hex",
      dstTextarea: "",

      // type BufferEncoding = "ascii" | "utf8" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "latin1" | "binary" | "hex";
      //原始数据编码类型
      charDataTypeList: [
        { value: "utf8", idx: "1" },
        { value: "ascii", idx: "2" },
        { value: "latin1", idx: "3" },
        { value: "ucs2", idx: "4" }
      ],
      charDataType: "utf8",

      encryptTypeList: [
        { value: "DES", idx: "1" },
        { value: "3DES", idx: "2" },
        { value: "AES", idx: "3" },
        { value: "SM4", idx: "4" }
      ],
      encryptType: "DES",

      //密钥数据类型
      encryptStringTypeList: [
        { value: "plain", idx: "1" },
        { value: "hex", idx: "2" },
        { value: "base64", idx: "3" }
      ],
      encryptStringType: "plain",
      srcSecretTextarea: "",
      encryptKeyTextarea: "",

      //初始化向量
      initVectorStringTypeList: [
        { value: "plain", idx: "1" },
        { value: "hex", idx: "2" },
        { value: "base64", idx: "3" }
      ],
      initVectorStringType: "plain",
      srcInitVectorTextarea: "",

      //分组模式
      blockTypeList: [
        { value: "ECB", idx: "1" },
        { value: "CBC", idx: "2" },
        { value: "CFB", idx: "3" },
        { value: "OFB", idx: "4" },
        { value: "CTR", idx: "5" }
      ],
      blockType: "ECB",

      //补位
      paddingTypeList: [
        { value: "PKCS7", idx: "1" },
        { value: "PKCS5", idx: "2" },
        { value: "Zero", idx: "3" },
        { value: "ANSIX923", idx: "4" },
        { value: "ISO10126", idx: "5" }
      ],
      paddingType: "PKCS7"
    };
  },
  computed: {
    showLowerCaseBtn: function() {
      return this.dstDataType == "hex" ? true : false;
    },

    //是否显示原始数据类型编码
    srcCharDataShow: function() {
      return this.srcDataType == "plain" ? true : false;
    }
  },
  methods: {
    fEncrypt: function(type) {




      // let _ALPHA = "cdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZab";
      //
      // let bs = new LBXCustomBase64();
      // bs.initCustomEncodeChars(_ALPHA,'=');
      //
      //
      // let bs64 = bs.encode("1234567890");
      // console.log(bs64);
      //
      // let dbs64 = bs.decode(bs64);
      // console.log(dbs64);
      //
      //
      //
      // console.log("type" + type);

      if (this.encryptType == "SM4") {
        this.fSM4Encrypt(type);
        return;
      }

      // console.log("sm3:"+sm3("12345678"));

      let key = null;
      switch (this.encryptStringType) {
        case "hex":
          key = Crypto.enc.Hex.parse(this.encryptKeyTextarea);
          break;
        case "base64":
          key = Crypto.enc.Base64.parse(this.encryptKeyTextarea);
          break;
        case "plain":
        default:
          {
            key = Crypto.enc.Utf8.parse(this.encryptKeyTextarea);
          }
          break;
      }

      console.log("key:" + this.encryptKeyTextarea);

      let blockMode = null;

      switch (this.blockType) {
        case "ECB":
          blockMode = Crypto.mode.ECB;
          break;
        case "CBC":
          blockMode = Crypto.mode.CBC;
          break;
        case "CFB":
          blockMode = Crypto.mode.CFB;
          break;
        case "OFB":
          blockMode = Crypto.mode.OFB;
          break;
        case "CTR":
          blockMode = Crypto.mode.CTR;
          break;
        default:
          {
            blockMode = Crypto.mode.ECB;
          }
          break;
      }

      // var inputBytes = Hex.utf8StrToBytes('11');

      console.log("block:" + this.blockType);
      if (this.blockType != "ECB") {
        console.log(this.srcInitVectorTextarea.length);
        if (this.isEmpty(this.srcInitVectorTextarea)) {
          this.dstTextarea = "初始化向量不能为空";
          return;
        }
      }

      let vector = null;
      switch (this.initVectorStringType) {
        case "hex":
          vector = Crypto.enc.Hex.parse(this.srcInitVectorTextarea);
          break;
        case "base64":
          vector = Crypto.enc.Base64.parse(this.srcInitVectorTextarea);
          break;
        case "plain":
        default:
          {
            vector = Crypto.enc.Utf8.parse(this.srcInitVectorTextarea);
          }
          break;
      }

      let padding = null;
      switch (this.paddingType) {
        case "PKCS7":
        case "PKCS5":
          padding = Crypto.pad.Pkcs7;
          break;
        case "Zero":
          padding = Crypto.pad.ZeroPadding;
          break;
        case "ANSIX923":
          padding = Crypto.pad.AnsiX923;
          break;
        case "ISO10126":
          padding = Crypto.pad.Iso10126;
          console.log(
            "这是填充方式的一种，旨将原文的长度边长组的大小的整数倍" +
              "最后一个填充是填充的字节数，其它位随机数。所以每次加密结果不一样"
          );
          break;
      }

      console.log(blockMode + padding);

      let encrypted = null;
      // let encrypted1 = null;
      if (type == "en") {
        let src = null;
        switch (this.srcDataType) {
          case "hex":
            src = Crypto.enc.Hex.parse(this.srcTextarea);
            break;
          case "base64":
            src = Crypto.enc.Base64.parse(this.srcTextarea);
            break;
          case "plain":
          default:
            {
              src = Crypto.enc.Utf8.parse(this.srcTextarea);
            }
            break;
        }
        console.log("src:" + this.srcTextarea);

        switch (this.encryptType) {
          case "DES":
            encrypted = Crypto.DES.encrypt(src, key, {
              iv: vector,
              mode: blockMode,
              padding: padding
            });

            break;
          case "3DES":
            encrypted = Crypto.TripleDES.encrypt(src, key, {
              iv: vector,
              mode: blockMode,
              padding: padding
            });
            break;
          case "AES":
            encrypted = Crypto.AES.encrypt(src, key, {
              iv: vector,
              mode: blockMode,
              padding: padding
            });
            break;
          case "SM4":
            break;
        }

        if (this.dstDataType == "hex") {
          let dst = encrypted.ciphertext.toString().toUpperCase();
          console.log(dst);
          this.dstTextarea = dst;
        } else {
          //base64
          let dst = encrypted;
          console.log(dst);
          this.dstTextarea = dst;
        }
      } else {
        let src = null;
        switch (this.srcDataType) {
          case "hex":
            src = Crypto.enc.Hex.parse(this.srcTextarea);
            src = Crypto.enc.Base64.stringify(src);
            break;
          case "base64":
            src = Crypto.enc.Base64.parse(this.srcTextarea);
            src = Crypto.enc.Base64.stringify(src);
            break;
          case "plain":
          default:
            {
              src = Crypto.enc.Utf8.parse(this.srcTextarea);
              src = Crypto.enc.Base64.stringify(src);
            }
            break;
        }
        console.log("src:" + this.srcTextarea);

        console.log("decrypt");
        switch (this.encryptType) {
          case "DES":
            console.log("decrypt DES");

            encrypted = Crypto.DES.decrypt(src, key, {
              iv: vector,
              mode: blockMode,
              padding: padding
            });
            console.log("decrypt DES");

            break;
          case "3DES":
            encrypted = Crypto.TripleDES.decrypt(src, key, {
              iv: vector,
              mode: blockMode,
              padding: padding
            });
            break;
          case "AES":
            encrypted = Crypto.AES.decrypt(src, key, {
              iv: vector,
              mode: blockMode,
              padding: padding
            });
            break;
        }

        let decryptedStr;
        switch (this.dstDataType) {
          case "hex":
            decryptedStr = encrypted.toString(Crypto.enc.Hex);
            console.log("de:" + decryptedStr);
            this.dstTextarea = decryptedStr;
            break;
          case "base64":
            decryptedStr = encrypted.toString(Crypto.enc.Base64);
            this.dstTextarea = decryptedStr;
            break;
          default:
            decryptedStr = encrypted.toString(Crypto.enc.Utf8);
            this.dstTextarea = decryptedStr;
            break;
        }
      }
    },

    fSM4Encrypt: function(type) {
      //encrypt
      let srcHex = null;
      switch (this.srcDataType) {
        case "hex":
          srcHex = this.srcTextarea;
          break;
        case "base64":
          srcHex = Crypto.enc.Base64.parse(this.srcTextarea).toString();
          break;
        case "plain":
        {
          srcHex = Crypto.enc.Utf8.parse(this.srcTextarea).toString();
        }
        break;
        default:
          {
            srcHex = Crypto.enc.Utf8.parse(this.srcTextarea).toString();
          }
          break;
      }
      console.log("srcHex:" + srcHex);

      //待加密byte
      let inputBytes = Hex.decode(srcHex);

      let keyHex = null;
      switch (this.encryptStringType) {
        case "hex":
          keyHex = this.encryptKeyTextarea;
          break;
        case "base64":
          keyHex = Crypto.enc.Base64.parse(this.encryptKeyTextarea).toString();
          break;
        case "plain":
        default:
          {
            keyHex = Crypto.enc.Utf8.parse(this.encryptKeyTextarea).toString();
          }
          break;
      }
      console.log("keyHex:" + keyHex);

      //加密密钥byte
      let keyBytes = Hex.decode(keyHex);

      let vectorHex = null;
      switch (this.initVectorStringType) {
        case "hex":
          vectorHex = this.srcInitVectorTextarea;
          break;
        case "base64":
          vectorHex = Crypto.enc.Base64.parse(
            this.srcInitVectorTextarea
          ).toString();
          break;
        case "plain":
        default:
          {
            vectorHex = Crypto.enc.Utf8.parse(
              this.srcInitVectorTextarea
            ).toString();
          }
          break;
      }
      console.log("vectorHex:"+vectorHex);
      let vectorBytes = Hex.decode(vectorHex);

      // paddingTypes 1: pkcs7padding 2:ANSIX923Padding 3:ISO10126Padding 4:ZeroPadding
      let padding = null;
      switch (this.paddingType) {
        case "PKCS7":
        case "PKCS5":
          padding = 1;
          break;
        case "Zero":
          padding = 4;
          break;
        case "ANSIX923":
          padding = 2;
          break;
        case "ISO10126":
          padding = 3;
          break;
      }

      switch (this.blockType) {
        case "ECB":
          {
            let sm4 = new SM4();

            let cipher;
            if (type == "en") {
              cipher = sm4.encrypt_ecb(keyBytes, inputBytes, padding);
            } else {
              cipher = sm4.decrypt_ecb(keyBytes, inputBytes, padding);
            }

            this.dstTextarea = Hex.encode(cipher, 0, cipher.length);

            if (this.dstDataType == "base64") {
              this.dstTextarea = Crypto.enc.Hex.parse(
                this.dstTextarea
              ).toString(Crypto.enc.Base64);
            }
          }
          break;
        case "CBC":
          {
            let sm4 = new SM4();
            let cipher;
            if (type == "en") {
              cipher = sm4.encrypt_cbc(keyBytes, vectorBytes, inputBytes, padding);
            } else {
              cipher = sm4.decrypt_cbc(keyBytes, vectorBytes, inputBytes, padding);
            }
            this.dstTextarea = Hex.encode(cipher, 0, cipher.length);

            if (this.dstDataType == "base64") {
              this.dstTextarea = Crypto.enc.Hex.parse(
                this.dstTextarea
              ).toString(Crypto.enc.Base64);
            }
          }
          break;
        case "CFB":
          {
            let sm4 = new SM4();
            let cipher;
            if (type == "en") {
              cipher = sm4.encrypt_cfb(keyBytes, vectorBytes, inputBytes, padding);
            } else {
              cipher = sm4.decrypt_cfb(keyBytes, vectorBytes, inputBytes, padding);
            }
            this.dstTextarea = Hex.encode(cipher, 0, cipher.length);

            if (this.dstDataType == "base64") {
              this.dstTextarea = Crypto.enc.Hex.parse(
                this.dstTextarea
              ).toString(Crypto.enc.Base64);
            }
          }
          break;
        default:
          {
            this.dstTextarea = "暂不支持该分组模式";
          }
          break;
      }
    },

    isEmpty: function(obj) {
      if (typeof obj == "undefined" || obj == null || obj == "") {
        return true;
      } else {
        return false;
      }
    },

    fLowerCase: function() {
      this.dstTextarea = this.dstTextarea.toLowerCase();

      var plainUtf8 = "1111";

      let plainBuffer = Buffer.from(plainUtf8, "utf-8");

      //-> hex
      let hex = plainBuffer.toString("hex");
      console.log("hex:" + hex);

      var wordArray = Crypto.enc.Hex.parse(hex);
      console.log(wordArray);

      // Encrypt
      let ciphertext = Crypto.AES.encrypt(
        wordArray,
        "secret key 123"
      ).toString();
      //base64
      console.log("encrypt base64:" + ciphertext);

      // Decrypt
      let bytes = Crypto.AES.decrypt(ciphertext, "secret key 123");
      // var decryptedData = JSON.parse(bytes.toString(Crypto.enc.Utf8));

      console.log(bytes); // [{id: 1}, {id: 2}]

      //hex
      console.log(bytes.toString());

      console.log(Buffer.from(bytes.toString(), "hex").toString("utf8"));

      console.log("above plain");

      //->base64
      let base64 = plainBuffer.toString("base64");
      console.log("base64:" + base64);

      //->string utf-8
      let utf8 = plainBuffer.toString("utf-8");
      console.log("utf8:" + utf8);

      //byte数组
      console.log(typeof plainBuffer.buffer);
      console.log(plainBuffer.buffer);

      console.log("hex to buf:");
      console.log(Buffer.from(hex, "hex"));

      let str1 = Buffer.from(hex, "hex").toString("utf-8");
      console.log("hex to utf-8 string:" + str1);

      //json与string相互转换
      this.json2String();

      //test encrpto
      this.testEncrypto();
    },
    hexToString: function(hex) {
      var arr = hex.split("");
      var out = "";

      for (var i = 0; i < arr.length / 2; i++) {
        var tmp = "0x" + arr[i * 2] + arr[i * 2 + 1];
        var charValue = String.fromCharCode(tmp);
        out += charValue;
      }
      return out;
    },

    json2String: function() {
      //json,注意手动拼写格式
      let json = '{ "name": "cxh", "sex": "man" }';
      // let json  = { name: "cxh", sex: "man" };

      if (typeof json == "string") {
        //string->json
        console.log("string object");
        let str;
        try {
          str = JSON.parse(json);
          console.log("string->json" + str);
        } catch (e) {
          console.log("err:" + str);
        }
      } else {
        //json -> string

        let jsonobj = JSON.stringify(json);

        console.log("json->string:" + jsonobj + typeof jsonobj);
      }
    },
    testEncrypto: function() {
      console.log("test encrypto");

      let data = [{ id: 1 }, { id: 2 }];

      // Encrypt
      let ciphertext = Crypto.AES.encrypt(
        JSON.stringify(data),
        "secret key 123"
      ).toString();
      //base64
      console.log(ciphertext);

      // Decrypt
      let bytes = Crypto.AES.decrypt(ciphertext, "secret key 123");
      // var decryptedData = JSON.parse(bytes.toString(Crypto.enc.Utf8));

      console.log(bytes); // [{id: 1}, {id: 2}]

      //hex
      console.log(bytes.toString());

      console.log(Buffer.from(bytes.toString(), "hex").toString("utf8"));
    }
  },
  created() {
    // 方便控制台获取当前vue进行数据调试
    window.encrypt = this;
  }
};
</script>

<style scoped>
.el-main {
  background-color: #e9eef3;
  color: #333;
  text-align: center;
  line-height: 50px;
}
.left {
  text-align: left;
}

.el-aside {
  display: block;
  position: relative;
  /*overflow-y: scroll;*/
  /*background-color: #324157 !important;*/
  width: 300px;
  border-left-color: #c8c8c8;
  border-left-style: solid;
  border-left-width: 1px;
}
</style>
